package dsx.bizServer;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import dsx.iot.IotPipeContext;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import dsx.biz._Biz;
import dsx.console.DsxConsole;
import dsx.inf.IBizServer;
import dsx.inf.IBizStartModule;
import dsx.inf.IConverter;
import dsx.inf.IDataTransfer;
import dsx.iot.IIotAgency;
import dsx.iot.IIotHandler;
import dsx.iot._IotData;
import dsx.log.ServLog;

public class BizServerIot implements IBizServer {
	final String encoding = "UTF-8";

	String serverName;
	String libPath = "";
	IDataTransfer dataTransfer = null;
	IConverter dataConverter = null;
	IBizStartModule startModule = null;
	IIotAgency iotAgency = null;

	int status = 0; // 状态：0 关闭，1 开启，2 正在关闭
	HashMap<String, _Biz> bizMap = new HashMap<String, _Biz>();

	int busyCnt = 0;

	private void incBusyCnt() {
		synchronized (this) {
			busyCnt++;
		}
	}

	private void decBusyCnt() {
		synchronized (this) {
			busyCnt--;
			if (status == 2 && busyCnt == 0) {
				status = 0;
				try {
					if (startModule != null)
						startModule.finalize();
				} catch (Exception ex) {
				}
			}
		}
	}

	@Override
	public void init(String serverName, String libPath, IDataTransfer dataTransfer, IConverter dataConverter) {
		this.serverName = serverName;
		this.libPath = libPath;
		this.dataTransfer = dataTransfer;
		this.dataConverter = dataConverter;
		loadBizMap("");
	}

	@Override
	public boolean start() {
		synchronized (this) {
			if (status != 0)
				return false;
			if (!initIotAgency())
				return false;
			if (!initStartModule())
				return false;
			status = 1;
			DsxConsole.out("server name:" + serverName + ",lib path:" + libPath, "iot biz server start", ServLog.info);
			return true;
		}
	}

	private boolean initIotAgency() {
		try {
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document document = db.parse(new File(String.format("%siotBiz.xml", libPath)));
			Element root = document.getDocumentElement();
			NodeList modules = root.getElementsByTagName("IotAgency");
			if (modules != null && modules.getLength() > 0) {
				NodeList tmp = ((Element) modules.item(0)).getElementsByTagName("class");
				String className = "";
				if (tmp.getLength() > 0)
					className = tmp.item(0).getTextContent();
				iotAgency = (IIotAgency) Class.forName(className).newInstance();
			}
			return true;
		} catch (Exception ex) {
			DsxConsole.out(ex.getMessage(), "iotBiz", ServLog.error);
			return false;
		}
	}

	private boolean initStartModule() {
		try {
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document document = db.parse(new File(String.format("%siotBiz.xml", libPath)));
			Element root = document.getDocumentElement();
			NodeList modules = root.getElementsByTagName("Server");
			if (modules != null && modules.getLength() > 0) {
				NodeList tmp = ((Element) modules.item(0)).getElementsByTagName("class");
				String className = "";
				if (tmp.getLength() > 0)
					className = tmp.item(0).getTextContent();

				startModule = (IBizStartModule) Class.forName(className).newInstance();
				startModule.initialize();
			}
			return true;
		} catch (Exception ex) {
			DsxConsole.out(ex.getMessage(), "biz", ServLog.error);
			return false;
		}
	}

	@Override
	public void stop() {
		synchronized (this) {
			if (busyCnt == 0) {
				status = 0;
				try {
					if (startModule != null)
						startModule.finalize();
				} catch (Exception ex) {
				}
			} else {
				status = 2;
			}
		}
	}

	@Override
	public int getStatus() {
		return status;
	}

	@Override
	public void handle(Object pipe, byte[] data) {
		if (status != 1 || dataTransfer == null || dataConverter == null)
			return;
		incBusyCnt();
		try {
			_IotData pack = (_IotData) dataConverter.toObject(data, _IotData.class);
			// 只处理请求包和信息包
			if (pack.getType() == 1)
				return;
			if (iotAgency != null) {
				iotAgency.connect(pack.getSrc(), pipe);
			}
			String inf = pack.getInf();
			if (inf.isEmpty())
				return;
			// 根据命令字匹配业务
			_Biz biz = getBiz(inf);
			if (biz == null)
				return;
			// 将数据包转化为对象
			Object req;
			req = dataConverter.toObject(dataConverter.toString(pack.getParam()), Class.forName(biz.getReqClass()));
			// 调用处理方法
			IotPipeContext.set(pipe);
			Object answ = ((IIotHandler) req).handle(pack);
			if (pack.getType() == 0) {
				pack.setType(1);
				pack.setAuth("");
				pack.setSrc(serverName);
				pack.setParam(answ);
				// 返回值转数据包并发送
				dataTransfer.send(pipe, dataConverter.toBytes(pack));
			}
		} catch (Exception ex) {
			DsxConsole.out("error:" + ex.getMessage(), "biz", ServLog.error);
		} finally {
			decBusyCnt();
		}
	}

	@Override
	public ArrayList<_Biz> getBizList() {
		synchronized (this) {
			ArrayList<_Biz> lst = new ArrayList<_Biz>();
			for (Entry<String, _Biz> entry : bizMap.entrySet())
				lst.add(entry.getValue());
			return lst;
		}
	}

	private void loadBizMap(String libName) {
		try {
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document document = db.parse(new File(String.format("%siotBiz.xml", libPath)));
			Element root = document.getDocumentElement();
			NodeList modules = root.getElementsByTagName("Module");
			int moduleNum = modules.getLength();
			for (int i = 0; i < moduleNum; i++) {
				_Biz biz = new _Biz();
				NodeList tmp = ((Element) modules.item(i)).getElementsByTagName("cmd");
				if (tmp.getLength() > 0)
					biz.setInf(tmp.item(0).getTextContent());
				tmp = ((Element) modules.item(i)).getElementsByTagName("name");
				if (tmp.getLength() > 0)
					biz.setName(tmp.item(0).getTextContent());
				tmp = ((Element) modules.item(i)).getElementsByTagName("reqClass");
				if (tmp.getLength() > 0)
					biz.setReqClass(tmp.item(0).getTextContent());
				if (!biz.getInf().isEmpty()) {
					this.bizMap.put(biz.getInf(), biz);
				}
			}
		} catch (Exception ex) {
			DsxConsole.out(ex.getMessage(), "biz", ServLog.error);
		}
	}

	private _Biz getBiz(String cmd) {
		synchronized (this) {
			try {
				return bizMap.get(cmd);
			} catch (Exception ex) {
				DsxConsole.out(ex.getMessage(), "biz", ServLog.warn);
				return null;
			}
		}
	}

}
